#include "JsonRpcMessageParser.h"
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonValue>
#include <QStringList>
#include <QDebug>

JsonRpcMessageParser::JsonRpcMessageParser()
{
}

bool JsonRpcMessageParser::validateMessage(const QJsonObject& message)
{
    if (!message.contains("jsonrpc") || message.value("jsonrpc").toString() != "2.0") {
        return false;
    }

    if (message.contains("method")) {
        if (message.contains("id")) {
            return validateRequest(message);
        } else {
            return validateNotification(message);
        }
    } else if (message.contains("result") || message.contains("error")) {
        return validateResponse(message);
    }

    return false;
}

QString JsonRpcMessageParser::parseMethodName(const QJsonObject& request)
{
    if (!validateMessage(request)) {
        return QString();
    }

    if (request.contains("method")) {
        QJsonValue methodValue = request.value("method");
        if (methodValue.isString()) {
            return methodValue.toString();
        }
    }

    return QString();
}

QJsonObject JsonRpcMessageParser::parseParameters(const QJsonObject& request)
{
    if (!validateMessage(request)) {
        return QJsonObject();
    }

    if (request.contains("params")) {
        QJsonObject paramsValue = request.value("params").toObject();
        return paramsValue;
    }

    return QJsonObject();
}

bool JsonRpcMessageParser::isNotification(const QJsonObject& message)
{
    if (!validateMessage(message)) {
        return false;
    }

    // Notification has method but no id field
    return message.contains("method") && !message.contains("id");
}

bool JsonRpcMessageParser::validateRequest(const QJsonObject& message) const
{
    QStringList requiredFields = {"jsonrpc", "method", "id"};
    
    if (!hasRequiredFields(message, requiredFields)) {
        return false;
    }

    if (message.value("jsonrpc").toString() != "2.0") {
        return false;
    }

    QJsonValue methodValue = message.value("method");
    if (methodValue.toString(QString()).isEmpty()) {
        return false;
    }

    // Validate id is string or number (not null and not undefined)
    QJsonValue idValue = message.value("id");
    if (idValue.isNull() || idValue.isUndefined() || 
        (!idValue.isString() && !idValue.isDouble())) {
        return false;
    }

    // Parameters are optional, but if present must be object (as per requirements)
    if (message.contains("params")) {
        QJsonValue paramsValue = message.value("params");
        if (!paramsValue.isObject()) {
            return false;
        }
    }

    return true;
}

bool JsonRpcMessageParser::validateResponse(const QJsonObject& message) const
{
    QStringList requiredFields = {"jsonrpc", "id"};

    if (!hasRequiredFields(message, requiredFields)) {
        return false;
    }

    // Validate jsonrpc version
    if (message.value("jsonrpc").toString() != "2.0") {
        return false;
    }

    bool hasResult = message.contains("result");
    bool hasError = message.contains("error");
    if ( (hasResult && hasError) || (!hasResult && !hasError) ) {
        return false;
    }

    QJsonValue idValue = message.value("id");
    if (idValue.isNull() || idValue.isUndefined() ||
        (!idValue.isString() && !idValue.isDouble())) {
        return false;
    }

    // Validate error object structure if present
    if (hasError) {
        QJsonValue errorValue = message.value("error");
        if (!errorValue.isObject()) {
            return false;
        }

        QJsonObject errorObject = errorValue.toObject();
        if (!errorObject.contains("code") || !errorObject.contains("message")) {
            return false;
        }

        QJsonValue codeValue = errorObject.value("code");
        if (!codeValue.isDouble()) {
            return false;
        }

        QJsonValue messageValue = errorObject.value("message");
        if (!messageValue.isString()) {
            return false;
        }
    }

    return true;
}

bool JsonRpcMessageParser::validateNotification(const QJsonObject& message) const
{
    QStringList requiredFields = {"jsonrpc", "method"};
    
    if (!hasRequiredFields(message, requiredFields)) {
        return false;
    }

    if (message.value("jsonrpc").toString() != "2.0") {
        return false;
    }

    QJsonValue methodValue = message.value("method");
    if (!methodValue.isString() || methodValue.toString().isEmpty()) {
        return false;
    }

    if (message.contains("id")) {
        return false;
    }

    // Parameters are optional, but if present must be object (as per requirements)
    if (message.contains("params")) {
        QJsonValue paramsValue = message.value("params");
        if (!paramsValue.isObject()) {
            return false;
        }
    }
    return true;
}

bool JsonRpcMessageParser::hasRequiredFields(const QJsonObject& message, const QStringList& requiredFields) const
{
    for (const QString& field : requiredFields) {
        if (!message.contains(field) || message.value(field).isUndefined()) {
            return false;
        }
    }
    return true;
}
